import re

from selenium.common.exceptions import NoSuchElementException

from common.functions import get_xpath
from common.decorators import log4gs


@log4gs
class VueTable(object):
    """页面的列表，包括翻页"""
    tableClassName = "ivu-table"
    tableTitleClassName = "ivu-table-title"
    tableHeaderClassName = "ivu-table-header"
    tableBodyClassName = "ivu-table-body"
    tableTipClassName = "ivu-table-tip"
    tableCellClassName = "ivu-table-cell"

    btnClassName = "ivu-btn"

    titleTextClassName = 'gridTitle'

    def __init__(self, index=0):
        """
        :param index: 要获取的表在当前页的序号，一般一个页面就一个表，一次默认为0

        使用方法：
            class Table(VueTable):
                def __init__(self, index=None):
                    super(Table, self).__init__(index=index)
            table = Table(index=0)   # 当前页第一个表
        """
        if not isinstance(index, int):
            raise ValueError('index要求是整数')
        self.index = index

    def __get__(self, instance, owner):
        self.driver = instance.driver
        self.table = self.driver.find_elements_by_class_name(self.tableClassName)[self.index]
        self.supply = self.table
        ### title_ele表示标题所在那一行的元素
        self.title_element =  self.__get_element(self.tableTitleClassName)
        ### 所有的列名
        self.header_element = self.__get_element(self.tableHeaderClassName)
        ### 表正文
        self.body_element = self.__get_element(self.tableBodyClassName)
        ### 表提示信息（没有数据时的提示信息）
        self.tip_element = self.__get_element(self.tableTipClassName)

        return self

    @property
    def title(self):
        """表的标题"""
        return self.title_element.find_element_by_class_name(self.titleTextClassName).text.strip()

    @property
    def all_headers(self):
        """
        将表的所有列名合在一起
        :return: 所有列名组成的字符串，用中文顿号（、）隔开
        """
        cells = self.header_element.find_elements_by_class_name(self.tableCellClassName)
        str_ = ''
        for i, cell in enumerate(cells):
            if cell.text:
                if i < len(cells) - 1:
                    str_ += cell.text.strip() + '、'
                else:
                    str_ += cell.text.strip()
        return str_

    @property
    def row_number(self):
        """表中一页的数目"""
        return len(self.body_element.find_elements_by_tag_name('tr'))

    @property
    def xpath(self):
        """获取浮窗的xpath"""
        try:
            xpath = get_xpath(self.driver, self.table)
            self.log.info("列表的xpath是：{}".format(xpath))
            return xpath
        except Exception:
            self.log.error("获取列表xpath失败", exc_info=True)

    def __get_element(self, class_name):
        try:
            return self.table.find_element_by_class_name(class_name)
        except Exception:
            self.log.error("在列表里面没有类名是：{}的元素".format(class_name))

    def get_btn(self, btn_name):
        """
        在ivu-table-title中根据按钮名称获取按钮元素
        :param btn_name: 按钮名称
        :return: 按钮元素
        """
        btns = self.title_element.find_elements_by_class_name(self.btnClassName)
        for btn in btns:
            if btn_name == btn.text.strip():
                return btn
        try:
            raise Exception("列表的标题区域没有找到{}按钮".format(btn_name))
        except Exception:
            self.log.error("列表的标题区域没有找到{}按钮".format(btn_name), exc_info=True)

    def get_row(self, keyword):
        """
        通过字符串精确匹配一行元素
        :param keyword: 一行中，任意一列的值
        :return: 表中某一个tr元素
        """
        rows = self.body_element.find_elements_by_tag_name('tr')
        if not rows:
            try:
                raise NoSuchElementException("列表里面没有tr标签")
            except NoSuchElementException:
                self.log.error("列表里面没有tr标签")
                return
        for row in rows:
            tds = row.find_elements_by_tag_name('td')
            for td in tds:
                if keyword == td.text.strip():
                    row.driver = self.driver   # 这里给它加driver属性是为了在common.vue.select.OperateSelect中运行js
                    return row
        try:
            raise NoSuchElementException('当前页没有匹配到单元格内容是"{}"的行'.format(keyword))
        except NoSuchElementException:
            self.log.error('当前页没有匹配到单元格内容是"{}"的行'.format(keyword), exc_info=True)


class VueTurnPage(object):
    """列表下面的翻页元素"""
    turnPageClassName = "gosun-page-wrap"
    totalClassName = "float-left"   # 包含总条数的div
    prevClassName = "gosun-page-button-prev"
    nextClassName = "gosun-page-button-next"
    currentClassName = "gosun-page-weight"
    inputClassName = "gosun-page-input"

    def __get__(self, instance, owner):
        self.driver = instance.driver
        self.page_wrap = self.driver.find_element_by_class_name(self.turnPageClassName)   # 翻页区域的元素
        self.supply = self.page_wrap
        self.total_element = self.page_wrap.find_element_by_class_name(self.totalClassName)   # 包含总数的元素
        self.prev_page = self.page_wrap.find_element_by_class_name(self.prevClassName)   # 上一页按钮
        self.next_page = self.page_wrap.find_element_by_class_name(self.nextClassName)   # 下一页按钮
        self.current_page = self.page_wrap.find_elements_by_class_name(self.currentClassName)[0].text.strip()   # 当前页数目
        self.input = self.page_wrap.find_element_by_class_name(self.inputClassName)   # 页数输入框

        return self

    def __set__(self, instance, value):
        pass

    @property
    def total_num(self):
        """获取所有的条数。实际格式：当前第1/3页，共 32 条。取其中的32"""
        text = self.total_element.text
        return re.findall('共 (\d+) 条', text)[0]

    @property
    def total_page(self):
        """获取所有的条数。实际格式：当前第1/3页，共 32 条。取其中的3"""
        text = self.total_element.text
        return re.findall('/(\d+)页', text)[0]